﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyUtils;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test.MyUtils
{
	[TestClass]
	public class TestDynamicAttachedProperties
	{
		class Sample
		{
			public string Data { get; set; }
		}

#if NET4
		[TestMethod]
		public void Should_allow_set_some_attached_property()
		{
			var test1 = new Sample { Data = "d1" };
			test1.Attached().MyData1 = "asd1";
			test1.Attached().MyData2 = "asd2";

			var test2 = new Sample { Data = "d1" };
			test2.Attached().MyData1 = "asd3";
			test2.Attached().MyData2 = "asd4";

			Assert.AreEqual("asd1", test1.Attached().MyData1);
			Assert.AreEqual("asd2", test1.Attached().MyData2);
			Assert.AreEqual("asd3", test2.Attached().MyData1);
			Assert.AreEqual("asd4", test2.Attached().MyData2);
		}

		[TestMethod]
		public void Should_not_leak_dynamic()
		{
			SelfMaintainable.CommonInterval = TimeSpan.FromSeconds(1);

			var wr_holder = new WeakReference(null);
			var wr_value = new WeakReference(null);

			{
				var testObject = new Sample();
				wr_holder.Target = testObject;
				{
					var testValue = new Sample { Data = "data" };
					wr_value.Target = testValue;
					testObject.Attached().Some = testValue;
					Assert.AreEqual("data", testObject.Attached().Some.Data);
					testValue = null;
				}

				Assert.IsTrue(wr_value.IsAlive);

				GC.Collect();
				GC.WaitForPendingFinalizers();

				Assert.IsTrue(wr_value.IsAlive);

				Assert.AreEqual("data", testObject.Attached().Some.Data);

				testObject = null;
			}

			Utils.WaitForEx(delegate
			{
				GC.Collect();
				GC.WaitForPendingFinalizers();
				return !wr_value.IsAlive;
			});

			Utils.WaitForEx(delegate
			{
				GC.Collect();
				GC.WaitForPendingFinalizers();
				return !wr_holder.IsAlive;
			});
		}
#endif

		[TestMethod]
		public void Should_allow_set_some_attached_property_for_net3()
		{
			var test1 = new Sample { Data = "d1" };
			test1.AttachedDictionary()["MyData1"] = "asd1";
			test1.AttachedDictionary()["MyData2"] = "asd2";
			var test2 = new Sample { Data = "d2" };
			test2.AttachedDictionary()["MyData1"] = "asd3";
			test2.AttachedDictionary()["MyData2"] = "asd4";

			Assert.AreEqual("asd1", test1.AttachedDictionary()["MyData1"]);
			Assert.AreEqual("asd2", test1.AttachedDictionary()["MyData2"]);
			Assert.AreEqual("asd3", test2.AttachedDictionary()["MyData1"]);
			Assert.AreEqual("asd4", test2.AttachedDictionary()["MyData2"]);
		}

		[TestMethod]
		public void Should_not_leak()
		{
			SelfMaintainable.CommonInterval = TimeSpan.FromSeconds(1);


			var wr_holder = new WeakReference(null);
			var wr = new WeakReference(null);

			{
				var testObject = new Sample();
				wr_holder.Target = testObject;

				{
					var testValue = new Sample {Data = "data"};
					wr.Target = testValue;
					testObject.AttachedDictionary()["some"] = testValue;
					Assert.AreEqual("data", testObject.AttachedDictionary().Get<Sample>("some").Data);
					testValue = null;
				}

				Assert.IsTrue(wr.IsAlive);

				GC.Collect();
				GC.WaitForPendingFinalizers();

				Assert.IsTrue(wr.IsAlive);

				Assert.AreEqual("data", testObject.AttachedDictionary().Get<Sample>("some").Data);

				testObject = null;
			}

			Utils.WaitForEx(delegate
			{
				GC.Collect();
				GC.WaitForPendingFinalizers();
				return !wr.IsAlive;
			});

			Utils.WaitForEx(delegate
			{
				GC.Collect();
				GC.WaitForPendingFinalizers();
				return !wr_holder.IsAlive;
			});
		}
	}
}
